using System;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.IO;

namespace Kollektiv.Extension
{
	/// <summary>
	/// General extensions for <see cref="System.String"/> class
	/// </summary>
	public static class System_String
	{
		/// <summary>
		/// Resolves an assembly string.
		/// </summary>
		/// <returns>
		/// The assembly.
		/// </returns>
		/// <param name='s'>
		/// string containing the assembly information.
		/// <example>
		/// <code>
		/// string myAssembly = "System.Xml";
		/// Assembly a = myAssembly.FindAssembly();
		/// </code>
		/// </example>
		/// </param>
		public static Assembly FindAssembly (this string s)
		{
            if (!string.IsNullOrEmpty(s))
            {
                string assemblyName = s;

                Assembly result = null;

                result = AppDomain.CurrentDomain.GetAssemblies().Where(x => x.FullName == assemblyName).FirstOrDefault();

                if (result == null)
                    result = AppDomain.CurrentDomain.Load(new AssemblyName(assemblyName));

                return result;
            }
            else
            {
                return null;
            }
		}
		
		/// <summary>
		/// Resolves a type string.
		/// </summary>
		/// <returns>
		/// The type.
		/// </returns>
		/// <param name='s'>
		/// string containing the type information.
		/// <example>
		/// <code>
		/// string myType = "System.Int32, System";
		/// Type t = myType.FindType();
		/// </code>
		/// </example>
		/// </param>
		public static Type FindType (this string s)
		{
            string[] sParts = s.Split (',');
			string typeName =  sParts[0];
			string assemblyName =  sParts.Length > 1 ? sParts[1] : null;
			
			Type result = null;			
			Assembly ass = null;
			
			if (string.IsNullOrEmpty (assemblyName)) {
				ass = AppDomain.CurrentDomain.GetAssemblies ().Where (x => x.GetType (typeName) != null).FirstOrDefault ();
			} else {
				ass = assemblyName.FindAssembly ();
			}
			
			if (ass != null) {
				result = ass.GetType (typeName);
			}
			
			return result;
		}
		
		/// <summary>
		/// Gets the SHA1 hash of as string.
		/// </summary>
		/// <returns>
		/// The hash.
		/// </returns>
		/// <param name='text'>
		/// String, in the most cases password to hash.
		/// </param>
		public static string GetPasswordHash (this string text)
		{
			var SHA1 = new SHA1CryptoServiceProvider ();

			byte[] arrayData;
			byte[] arrayResult;
			string result = null;
			string temp = null;

			arrayData = Encoding.ASCII.GetBytes (text);
			arrayResult = SHA1.ComputeHash (arrayData);
			for (int i = 0; i < arrayResult.Length; i++) {
				temp = Convert.ToString (arrayResult [i], 16);
				if (temp.Length == 1)
					temp = "0" + temp;
				result += temp;
			}
			return result;
		}

        /// <summary>
        /// Deserializes a string containing a data contract object.
        /// </summary>
        /// <typeparam name="T">Type of the object which should be deserialized</typeparam>
        /// <param name="serialized">Serialized string.</param>
        /// <returns>Deserialized object.</returns>
        public static T DeserializeDataContract<T>(this string serialized) where T : class
        {
            using (Stream ms = new MemoryStream(Encoding.UTF8.GetBytes(serialized)))
            {
                return ms.DeserializeDataContract<T>();
            }
        }

        /// <summary>
        /// Gets the bytes of a string using the default encoding
        /// </summary>
        /// <param name="s">The string.</param>
        /// <returns>Bytes of the string.</returns>
        public static byte[] GetBytes(this string s)
        {
            return s.GetBytes(Encoding.Default);
        }

        /// <summary>
        /// Gets the bytes of a string.
        /// </summary>
        /// <param name="s">The string.</param>
        /// <param name="encoding">The encoding to use.</param>
        /// <returns>Bytes of the string</returns>
        public static byte[] GetBytes(this string s, Encoding encoding)
        {
            return encoding.GetBytes(s);
        }

        /// <summary>
        /// Gets a stream of a string using the default encoding.
        /// </summary>
        /// <param name="s">The string.</param>
        /// <returns>Stream containing the string.</returns>
        public static Stream GetStream(this string s)
        {
            return s.GetStream(Encoding.Default);
        }

        /// <summary>
        /// Gets a stream of a string.
        /// </summary>
        /// <param name="s">The string.</param>
        /// <param name="encoding">The encoding to use.</param>
        /// <returns>Stream containing the string.</returns>
        public static Stream GetStream(this string s, Encoding encoding)
        {
            return new MemoryStream(s.GetBytes(encoding));
        }
	}	
}

